"""
  civciv.py
  http://civciv.googlecode.com
  Developer: Azer Koculu <http://azer.kodfabrik.com>
"""
from os import stat as flStat
from os.path import exists,isfile,isdir
from mimetypes import guess_type as guessMimeType
from rfc822 import formatdate as formatEpoch
from cgi import parse_qs
from paste.httpexceptions import HTTPNotFound
from paste.request import parse_formvars as getFormFields
from stat import ST_MTIME
from re import match
import logging

class Controller(object):
  
  def __init__(self,urlpatterns):
    self.urlpatterns = urlpatterns
  
  def __call__(self,environ,start_response):
    try:
      handler,arg = self.findHandler(environ.get("PATH_INFO"))
      arg = list(arg)
      arg.insert(0,Request(environ))
      response = handler(*arg)
    except HTTPNotFound:
      start_response('200 OK',[('content-type','text/html')])
      return ['<h1>Error 404-Not Found</h1>Civciv.py']
    start_response(response.statusCode,response.header)
    return response.content
    
  def findHandler(self,url):
    for pattern,handler in self.urlpatterns:
      result = match(pattern,url)
      if result:
        return handler,result.groups()
    raise HTTPNotFound

class Response(object):
  def __init__(self,content="",contentType=None):
    self.content = []
    self.header = []
    self.statusCode = "200 OK"
    self.write(content)
  
    if contentType:
      self.header.append(("Content-Type",contentType))
  
  def write(self,content):
    self.content.append(content)

class Request(object):
  def __init__(self,environ):
    self.__get = None
    self.__post = None
    self.__session = None
    self.META = environ
    self.method = environ.get('REQUEST_METHOD')

  @apply
  def session():
    def fget(self):
      if self.__session == None:
        try:
          self.__session = self.META['paste.session.factory']()
        except KeyError:
          raise KeyError, "Make sure MIDDLEWARE_CLASSES contains 'paste.session.SessionMiddleware' class."
      return self.__session
    return property(**locals())
  
  @apply
  def GET():
    def fget(self):
      if self.__get == None:
        qs = self.META.get('QUERY_STRING','')
        self.__get = qs and dict([ (part.count("=") and part or "%s="%part).split("=") for part in qs.split("&") ]) or {}
      return self.__get
      
    return property(**locals())
  
  @apply
  def POST():
    def fget(self):
      if self.__post == None:
        self.__post = self.method == "POST" and getFormFields(self.META) or {}
      return self.__post
    return property(**locals())

def static(docroot):
  isDir = isdir(docroot)
  isFile = isfile(docroot)
  assert isDir or isFile
  def app(environ,fname=''):
    path = isFile and docroot or ("%s/%s"%(docroot.rstrip("/"),fname))
    logging.info("Request to static file: %s"%path)
    if not exists(path) or not isfile(path):
      raise HTTPNotFound
    response = Response(open(path,'rb').read())
    stat = flStat(path)
    contentType = guessMimeType(path)
    response.header = [
      ('Content-Type', contentType and contentType[0] or 'text/plain' ),
      ('Content-Length',str(len("".join(response.content)))),
      ('Last-Modified',formatEpoch(stat[ST_MTIME]) )
    ]
    logging.info("|- type: %s, len:%s, lm: %s "%(response.header[0][1],response.header[1][1],response.header[2][1]))
    return response
  return app

def middlewareWrapper(app,conf):
  for mw in conf.MIDDLEWARE_CLASSES: app = mw(app)
  return app
  
def start(host,port,conf):
  from paste import httpserver
  app = middlewareWrapper(Controller(conf.urlpatterns),conf)
  if conf.DEBUG:
    from paste import evalexception
    evalexception.middleware.error_template = '''\n<html>\n<head>\n <title>Server Error</title>\n %(head_html)s\n</head>\n<body style='padding:0; margin:0;  background:#eee;'><h1 style="font:bold 24px Arial,sans-serif; color:#333; padding:20px; margin:0;">An error occured.<span style="padding:2px; background:rgb(255,255,0); color:rgb(255,0,0); font:bold 12px Arial;">civciv</span></h1><div style='padding:20px; border:1px solid #aaa; border-left:0; border-right:0; background:#fff;'>\n\n<div id="error-area" style="display: none; background-color: #600; color: #fff; border: 2px solid black">\n<div id="error-container"></div>\n<button onclick="return clearError()">clear this</button>\n</div>\n\n%(repost_button)s\n\n%(body)s\n\n</div></body>\n</html>\n'''
    app = evalexception.EvalException(app)
  httpserver.serve(app,host=host,port=port)

def WSGIHandler():
  import conf
  return middlewareWrapper(Controller(conf.urlpatterns),conf)

def test():
  logging.info("Creating test application..")
  return Controller(
      ( 
        (r'^/?$', lambda request: Response("<span style='background:yellow; color:green; padding:5px; font:bold 36px Times;'>It Works!</span><br /><span style='font:bold 14px Times; background:red; color:yellow; padding:3px;'>civciv.py</span>","text/html") ), 
      )
  )
  
if __name__ == "__main__":
  from sys import argv as sysargs
  '''
  if sysargs.count("--createconf"):
    logging.info("Creating conf.py file.")
    conf = open("conf.py","w")
    conf.write("\n".join([
      "from civciv import Response",
      "from paste.session import SessionMiddleware","",
      "DEBUG = True",
      "MIDDLEWARE_CLASSES = (",
      "  SessionMiddleware,",
      ")",
      "urlpatterns = (",
      "  (r'^/?$',lambda request: Response('This is page 1.<hr /><a href=\"/page2\">page2</a>','text/html')),",
      "  (r'^/page2/?$',lambda request: Response('This is page 2<hr /><a href=\"/\">page1</a>','text/html'))",
      ")"
    ]))
    conf.close()
    logging.info("conf.py has been created.stopping app..")
    exit()
    
  try:
    import conf
  except ImportError, err:
    logging.error("Could not import conf.py.Exception Info: %s"%err)
    from paste import httpserver
    httpserver.serve(test(),host="127.0.0.1",port="8000")
  '''
  import conf
  
  start(
    sysargs.count("-h") and sysargs[sysargs.index("-h")+1] or "127.0.0.1",
    sysargs.count("-p") and sysargs[sysargs.index("-p")+1] or "8000",
    conf
  )
